﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Mark.Sqlite.Entity;
using Mark.Sqlite.Attributes;

namespace Mark.Sqlite.Helper
{
	public abstract class TableMapper
	{
	    static readonly Dictionary<string, TableInfo> TableInfos = new Dictionary<string, TableInfo>();
		
		protected TableInfo MapEntity<T>(T entity)
		{
            var entityName = entity.GetType().FullName;

            //SE NAO EXISTIR DENTRO DO DICIONARIO O ADICIONAMOS
            if (!TableInfos.ContainsKey(entityName))
            {
                var info = new TableInfo
                    {
                        Table = GetTableName(entity),
                        Columns = GetColumns(entity)
                    };

                TableInfos.Add(entityName, info);
            }

            return TableInfos[entityName];
		}

		TableAttribute GetTableName<T>(T entity)
		{
			var customAttrib = entity.GetType().GetCustomAttributes(typeof(TableAttribute), false);

			if (customAttrib.Any())
			{
				var entityAttribute = customAttrib[0] as TableAttribute;
				if (entityAttribute != null)
				{
					entityAttribute.ClassName = entity.GetType().Name;
					
					if (string.IsNullOrEmpty(entityAttribute.TableName))
						entityAttribute.TableName = entityAttribute.ClassName;

					return entityAttribute;
				}
			}


			return new TableAttribute
				{
					ClassName = entity.GetType().Name,
					TableName = entity.GetType().Name
				};

		}


		HashSet<ColumnAttribute> GetColumns<T>(T entity)
		{
			var result = new HashSet<ColumnAttribute>();


			//VARRER TODAS AS PROPRIEDADES
			foreach (var propertyInfo in entity.GetType().GetProperties())
			{
				var columnInfo = new ColumnAttribute();

				//PEGAR O VALOR 
				columnInfo.PropertyInfo = propertyInfo;
				
				//PEGAR O NOME DA COLUNA, SE É CUSTOMIADO OU NAO
				var customAttrib = propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), false);

				var col = customAttrib.Any() ? customAttrib[0] as ColumnAttribute : null;

				if (col != null)
				{
					columnInfo.ColumnName = !string.IsNullOrEmpty(col.ColumnName) ? col.ColumnName : propertyInfo.Name;
					columnInfo.IsPrimaryKey = col.IsPrimaryKey;
					columnInfo.IsAutoIncrement = col.IsAutoIncrement;
					columnInfo.Lenght = col.Lenght;
					columnInfo.AllowNull = col.AllowNull;
				}
				else
				{
					columnInfo.ColumnName = propertyInfo.Name;	
				}
				


				//ADICONAR AO RESULTADO
				result.Add(columnInfo);
			}

			//SO PODE HAVER UM CAMPO AUTO INCEREMNTO POR TABELA
            if (result.Any() && result.Count(t => t.IsAutoIncrement) > 1)
            {
                var msg = string.Format("É permitido apenas uma coluna auto-incremento por tabela. Entidade {0}", entity.GetType().Name);
                throw new Exceptions.DuplicateAutoIncrementException(msg);
            }

            //SE HOUVER MAIS DE UMA CHAVE, E UMA SENDO AUTOINCREMNTO
            //SQLITE PERMITE APENAS UMA CHAVE COM AUTOINCREMENTO
		    if (result.Any() && result.Count(t => t.IsPrimaryKey) > 1 && result.Any(t => t.IsAutoIncrement))
		    {
		        throw new Exception(string.Format("Deve haver apenas uma PK quando houver coluna auto-incremento. Entidade {0}", entity.GetType().Name));
		    }



			return result;
		}

	}
}
